package com.tiancheng.trade.payment.channel.umsmop.util;

import com.tiancheng.trade.commom.core.utils.JsonUtil;
import com.tiancheng.trade.commom.core.utils.ForestHttpUtil;
import com.tiancheng.trade.payment.channel.umsmop.constants.ConfigBean;
import com.tiancheng.trade.payment.channel.umsmop.request.UmsMopTokenRequest;
import com.tiancheng.trade.payment.channel.umsmop.response.TokenResponse;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.message.BasicHeader;

import java.security.MessageDigest;
import java.util.Date;

/**
 * Created with IntelliJ IDEA.
 * User: ZHANGWEI
 * Date: 2016/12/5
 * Time: 15:41
 * 所属模块：
 * 功能说明：Open Token相关
 */
@Slf4j
public class OpenTokenUtil {
    private static final String constant_classname = OpenTokenUtil.class.getSimpleName();

    /**
     * token sha256签名算法
     *
     * @param appId
     * @param timestamp
     * @param nonce
     * @param appKey
     * @return
     */
    public static String generateSignature(String appId, String timestamp,
                                           String nonce, String appKey) {
        String plaintext = appId + timestamp + nonce + appKey;
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            digest.update(plaintext.getBytes());
            byte messageDigest[] = digest.digest();
            StringBuffer hexString = new StringBuffer();
            for (int i = 0; i < messageDigest.length; i++) {
                String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
                if (shaHex.length() < 2) {
                    hexString.append(0);
                }
                hexString.append(shaHex);
            }
            return hexString.toString();

        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return "";
    }


    /**
     * 获取token
     *
     * @param context
     * @return
     */
    public static TokenResponse getToken(OpenApiContext context) {
        int retry = 0;
        ConfigBean configBean = context.getConfigBean();
        TokenResponse acquiredToken = null;
        if (isTokenValid(context.getCurrentToken())
                && !isTokenTimeout(context.getCurrentToken())) {
            return context.getCurrentToken();
        }
        while (retry++ < configBean.getTokenAcquireReties()) {
            acquiredToken = acquireAccessToken(context);
            if (null != acquiredToken) {  //如果想根据请求token是否成功 用于重试 判断用if (null != acquiredToken.getAccessToken())
                break;
            } else if (retry < configBean.getTokenAcquireReties()) {
                try {
                    Thread.sleep(200);
                } catch (Exception e) {
                    log.error(constant_classname + " 重试token申请出错:" + e.getCause());
                }
            } else {
                log.error(constant_classname + " 申请token超过重试次数 bye-bye");
                break;
            }
        }
        return acquiredToken;
    }

    private static TokenResponse acquireAccessToken(OpenApiContext context) {
        String appId = context.getAppId();
        String appKey = context.getAppKey();
        ConfigBean configBean = context.getConfigBean();

        UmsMopTokenRequest tokenRequest = new UmsMopTokenRequest(appId, appKey);
        JSONObject jsonObj = JSONObject.fromObject(tokenRequest);
        TokenResponse tokenResponse;
        String url = context.getOpenServUrl().concat(configBean.getVersion()).concat(configBean.getTokenServiceCode());
        try {

            Header[] headers = new BasicHeader[]{new BasicHeader("content-type", "application/json")};

            String response = ForestHttpUtil.getInstance().doPostJson(url, jsonObj, headers);


            if (StringUtils.isBlank(response)) throw new Exception(constant_classname + "：服务提供方未返回");

            tokenResponse = JsonUtil.fromJson(response, TokenResponse.class);
            tokenResponse.setEffectTime(new Date());
            tokenResponse.setTimeout(tokenResponse.getExpiresIn());
            tokenResponse.setAheadInterval(configBean.getTokenAcquireAheadInterval());
            return tokenResponse;
        } catch (Exception e) {
            log.error(constant_classname + " exception:" ,e);
        }
        return null;
    }

    private static boolean isTokenValid(TokenResponse tokenBean) {
        return (null != tokenBean
                && org.apache.commons.lang.StringUtils.isNotBlank(tokenBean.getAccessToken())
                && null != tokenBean.getEffectTime()
                && tokenBean.getTimeout() > 0
                && tokenBean.getAheadInterval() > 0 && tokenBean.getTimeout() > tokenBean
                .getAheadInterval());
    }

    private static boolean isTokenTimeout(TokenResponse tokenBean) {
        int elapseInterval = (int) ((new Date().getTime() - tokenBean
                .getEffectTime().getTime()) / 1000);
        int maxEffectiveInterval = tokenBean.getTimeout()
                - tokenBean.getAheadInterval();
        boolean isTimeout = (elapseInterval > maxEffectiveInterval);
        if (isTimeout) {
            log.error(constant_classname + " exception:token过期了");
        }
        return isTimeout;
    }

}
